/*
 * $Library: Moyrax Core $
 * $Module: Default Prototype Extension $
 * $Date: 2008/01/28 23:35:17 $
 * $Rev: @REV $
 */
var $extend = function($target, $source, $keep, $callback) {
	$target = $target || this;

	if ( typeof $source == "function" )
		$source = $source();

	if ( !$source.length )
		$source = [$source];

	for ( var $i = 0; $i < $source.length; $i++ ){
		if ( typeof $source[$i] != "object" )
			continue;

		for ( var $p in $source[$i] ) {
			if ( $keep && $target[$p] )
				continue;

			$target[$p] = $source[$i][$p];

			if ( $ && $.isProc && $.isProc($callback) ) {
				if ( $callback.apply($target, [$p]) == BREAK )
					return(false);
			}
		}
	}

	return($target);
};

window.extend =
Function.prototype.extend =
Object.prototype.extend = function($source, $keep, $callback) {
	return( $extend(this, $source, $keep, $callback) );
};

String.prototype.extend({
	/**
	 * Elimina los espacios a ambos lados de la cadena.
	 */
	trim : function() {
		var sTrim = this.ltrim().rtrim();

		return(sTrim);
	},
	/**
	 * Elimina los espacios a la derecha de la cadena.
	 */
	rtrim : function() {
		return( this.replace(/(\x20)*$/, "") );
	},
	/**
	 * Elimina los espacios a la izquierda de la cadena.
	 */
	ltrim : function() {
		return( this.replace(/(\x20)*/, "") );
	}
});
Array.prototype.extend({
	/**
	 * Busca un elemento, y devuelve el índice,
	 * o null si no existe.
	 *
	 * @param spec  Elemento a buscar.
	 */
	exists : function(spec) {
		for ( var i = 0; i < this.length; i++) {
			if ( this[i] === spec )
				return(i);
		}

		return(null);
	},
	/**
	 * Recorre cada elemento y notifica a una callback
	 * cada item del array, incluído su índice.
	 *
	 * @param proc   Callback que recibirá los elementos.
	 * @param start  Índice del elemento desde el cual se comenzará a recorrer.
	 * @param end    Índice límite hasta donde recorrer.
	 * @param step   Cantidad de saltos por cada iteración.
	 * @param owner  Objeto en cuyo contexto se ejecutará el callback.
	 */
	each : function(proc, start, end, step, owner) {
		var r;

		end = end || this.length;

		for ( var i = start || 0; i < end; i += step || 1) {
			r = proc.apply(owner || this, [this[i], i]);

			if ( r == BREAK ) // Se canceló el bucle.
				break;
			else if ( r ) {
				return(r);
			}
		}

		return(false);
	},
	/**
	 * Agrega elementos al array. Si se especifican otros arrays,
	 * se agregarán también los elementos de esta última.
	 *
	 * @param items  Elementos que se agregarán.
	 */
	add : function(items) {
		var pItem;

		for ( var i = 0; i < arguments.length; i++) {
			pItem = arguments[i];

			if ( $.isArray(pItem) )
				for ( var m = 0; m < pItem.length; m++)
					this.push(pItem[m]);
			else
				this.push(pItem);
		}
	},
	/**
	 * Borra el array.
	 */
	clear : function() {
		this.splice(0, this.length)
	},
	/**
	 * Borra el array y lo reinicializa con los
	 * nuevos datos especificados.
	 *
	 * @param rstData  Elementos que se agregarán.
	 */
	reset : function(rstData){
		this.clear();
		this.add(rstData);
	},
	/**
	 * Devuelve el primer elemento de la lista.
	 */
	first : function() {
		return((this.length > 0) ? this[0] : false);
	},
	/**
	 * Devuelve el último elemento de la lista.
	 */
	last : function() {
		return((this.length > 0) ? this[this.length - 1] : false);
	}
});
$.extend({
	/**
	 * Verifica si la expresión es una función válida.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isProc : function(spec) {
		return( typeof spec === "function" );
	},
	/**
	 * Verifica si la expresión es una cadena (String) válida.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isStr : function(spec) {
		return( typeof spec === "string" );
	},
	/**
	 * Verifica si la expresión es un objeto válido.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isObj : function(spec) {
		return( typeof spec === "object" );
	},
	/**
	 * Verifica si la expresión es un número válido.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isNum : function(spec) {
		if ( !spec )
			return(null);

		return( typeof spec === "number" );
	},
	/**
	 * Verifica si la expresión es un array válido.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isArray : function(spec) {
		if ( !spec || !spec.constructor )
			return(false);

		return( spec.constructor.toString().indexOf("Array") > -1 );
	},
	/**
	 * Verifica si la expresión especificada es el objeto window.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isWindow : function(spec) {
		return( (spec.location && spec.location.href ) ? true : false )
	},
	/**
	 * Verifica si la expresión especificada tiene un valor definido.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isDef : function(spec,a) {
		return( (String(spec) != undefined) || (String(spec) == null) || false )
	},
	/**
	 * Verifica si la expresión especificada es una url local.
	 *
	 * @param spec  Expresión a evaluar.
	 */
	isLocal : function(url){
		return(!Boolean(url.match(/^(?:http.*:|ftp:)\/\//)));
	},
	/**
	 * Recorre cada elemento dentro de una colección.
	 *
	 * @param obj    Objeto que posee la colección en cuestión.
	 * @param prop   Nombre de la propiedad que contiene la colección.
	 * @param proc   Callback que recibirá los elementos.
	 * @param start  Índice del elemento desde el cual se comenzará a recorrer.
	 * @param end    Índice límite hasta donde recorrer.
	 * @param step   Cantidad de saltos por cada iteración.
	 * @param owner  Objeto en cuyo contexto se ejecutará el callback.
	 */
	walk : function(obj, prop, proc, start, end, step, owner){
		if ( !obj )
			return(false);

		var arr = this.array(obj, prop);

		if ( !arr.length ) {
			arr = [];

			for ( var p in obj )
				arr.push(p);
		}
		arr.each(function(p, i){
			if ( $.isProc(proc) )
				proc.apply(this, [p, i]);
		}, start, end, step, owner || obj);

		return(true);
	},
	array : function(obj, prop) {
		var arr = [];

		if ( prop )
			obj = obj[prop];

		if ( !obj ) return(false);

		for(var i = 0; i < obj.length; i++){
			arr.push(obj[i]);
		}

		return(arr);
	}
});

window.BASE = -1000;          // Valor base para las constantes definidas.
window.BREAK = BASE-1;        // Salir del bucle each.
window.CREATE_FAIL = BASE-2;  // Fallar al crear una instancia de objeto.
